package advancedKonwledgePdf.atomic;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * CAS ABA 问题
 *
 * 描述: 第一个线程取到了变量 x 的值 A，然后巴拉巴拉干别的事，总之就是只拿到了变量 x 的值
 * A。这段时间内第二个线程也取到了变量 x 的值 A，然后把变量 x 的值改为 B，然后巴拉巴拉干别
 * 的事，最后又把变量 x 的值变为 A （相当于还原了）。在这之后第一个线程终于进行了变量 x 的
 * 操作，但是此时变量 x 的值还是 A，所以 compareAndSet 操作是成功。
 *
 * 例子描述(可能不太合适，但好理解): 年初，现金为零，然后通过正常劳动赚了三百万，之后正常
 * 消费了（比如买房子）三百万。年末，虽然现金零收入（可能变成其他形式了），但是赚了钱是事
 * 实，还是得交税的！
 * */
public class AtomicIntegerDefectDemo {
    public static void main(String[] args) {
        defectOfABA();
    }

    static void defectOfABA() {
        final AtomicInteger atomicInteger = new AtomicInteger(1);
        Thread coreThread = new Thread(() -> {
            final int currentValue = atomicInteger.get();
            System.out.println(Thread.currentThread().getName() + " ---- -- currentValue=" + currentValue);
            // 这段目的：模拟处理其他业务花费的时间
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean casResult = atomicInteger.compareAndSet(1, 2);
            System.out.println(Thread.currentThread().getName() + " ------ currentValue=" + currentValue + ", finalValue=" + atomicInteger.get() + ", compareAndSet Result=" + casResult);
        });
        coreThread.start();
        // 这段目的：为了让 coreThread 线程先跑起来
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread amateurThread = new Thread(() -> {
            int currentValue = atomicInteger.get();
            boolean casResult = atomicInteger.compareAndSet(1, 2);
            System.out.println(Thread.currentThread().getName() + " ------ currentValue=" + currentValue + ", finalValue=" + atomicInteger.get() + ", compareAndSet Result=" + casResult);
            currentValue = atomicInteger.get();
            casResult = atomicInteger.compareAndSet(2, 1);
            System.out.println(Thread.currentThread().getName() + " ------ currentValue=" + currentValue + ", finalValue=" + atomicInteger.get() + ", compareAndSet Result=" + casResult);
        });
        amateurThread.start();
    }
}